package com.acdc.wechat.service;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.MediaType;
import org.springframework.http.converter.StringHttpMessageConverter;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.acdc.wechat.dto.WechatUserInfo;
import com.acdc.wechat.dto.WechatAuthResponse;
import com.acdc.wechat.utils.EncodingUtils;

import java.nio.charset.StandardCharsets;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;
import javax.annotation.PostConstruct;
import java.util.Iterator;
import java.util.Map;

@Service
public class WechatService {

    @Value("${wechat.pay.app-id}")
    private String appId;
    
    @Value("${wechat.pay.app-secret}")
    private String appSecret;
    
    private final RestTemplate restTemplate;
    private final ObjectMapper objectMapper = new ObjectMapper();
    
    // 缓存已使用的授权码，防止重复使用
    private final ConcurrentHashMap<String, Long> usedCodes = new ConcurrentHashMap<>();
    
    public WechatService() {
        // 配置RestTemplate以正确处理UTF-8编码
        this.restTemplate = new RestTemplate();
        
        // 设置字符串消息转换器，使用UTF-8编码，支持多种媒体类型
        StringHttpMessageConverter stringConverter = new StringHttpMessageConverter(StandardCharsets.UTF_8);
        stringConverter.setSupportedMediaTypes(java.util.Arrays.asList(
            MediaType.APPLICATION_JSON,
            MediaType.TEXT_PLAIN,
            MediaType.TEXT_HTML,
            MediaType.APPLICATION_OCTET_STREAM
        ));
        
        // 替换默认的字符串转换器
        this.restTemplate.getMessageConverters().removeIf(converter -> converter instanceof StringHttpMessageConverter);
        this.restTemplate.getMessageConverters().add(0, stringConverter);
    }
    
    /**
     * 通过授权码获取微信授权信息（包含access_token和openId）
     * 避免重复调用微信API
     */
    public WechatAuthResponse getAuthInfoByCode(String code) {
        // 检查授权码是否已被使用
        if (usedCodes.containsKey(code)) {
            throw new RuntimeException("授权码已被使用，请重新授权");
        }
        
        String url = String.format(
            "https://api.weixin.qq.com/sns/oauth2/access_token?appid=%s&secret=%s&code=%s&grant_type=authorization_code",
            appId, appSecret, code
        );
        
        String response = restTemplate.getForObject(url, String.class);
        try {
            JsonNode result = objectMapper.readTree(response);
            if (result.has("errcode")) {
                int errcode = result.get("errcode").asInt();
                String errmsg = result.get("errmsg").asText();
                
                // 特殊处理授权码已使用的错误
                if (errcode == 40163) {
                    // 标记该授权码为已使用
                    usedCodes.put(code, System.currentTimeMillis());
                    throw new RuntimeException("授权码已失效，请重新授权");
                }
                
                throw new RuntimeException("获取授权信息失败: " + errmsg + " (错误码: " + errcode + ")");
            }
            
            // 成功获取授权信息后，标记授权码为已使用
            usedCodes.put(code, System.currentTimeMillis());
            
            WechatAuthResponse authResponse = new WechatAuthResponse();
            authResponse.setAccessToken(result.get("access_token").asText());
            authResponse.setOpenId(result.get("openid").asText());
            authResponse.setScope(result.get("scope").asText());
            authResponse.setRefreshToken(result.get("refresh_token").asText());
            authResponse.setExpiresIn(result.get("expires_in").asInt());
            
            return authResponse;
        } catch (Exception e) {
            throw new RuntimeException("解析授权响应失败: " + e.getMessage());
        }
    }
    
    public String getOpenIdByCode(String code) {
        String url = String.format(
            "https://api.weixin.qq.com/sns/oauth2/access_token?appid=%s&secret=%s&code=%s&grant_type=authorization_code",
            appId, appSecret, code
        );
        
        String response = restTemplate.getForObject(url, String.class);
        try {
            JsonNode result = objectMapper.readTree(response);
            if (result.has("errcode")) {
                throw new RuntimeException("获取openId失败: " + response);
            }
            return result.get("openid").asText();
        } catch (Exception e) {
            throw new RuntimeException("解析响应失败: " + e.getMessage());
        }
    }
    
    public WechatUserInfo getUserInfo(String openId, String accessToken) {
        String url = String.format(
            "https://api.weixin.qq.com/sns/userinfo?access_token=%s&openid=%s&lang=zh_CN",
            accessToken, openId
        );
        
        String response = restTemplate.getForObject(url, String.class);
        try {
            JsonNode result = objectMapper.readTree(response);
            if (result.has("errcode")) {
                throw new RuntimeException("获取用户信息失败: " + response);
            }
            
            WechatUserInfo userInfo = new WechatUserInfo();
            userInfo.setOpenId(result.get("openid").asText());
            
            // 处理昵称编码问题
            String nickname = result.get("nickname").asText();
            nickname = EncodingUtils.fixWechatNickname(nickname);
            nickname = EncodingUtils.cleanText(nickname);
            userInfo.setNickname(nickname);
            
            userInfo.setSex(result.get("sex").asInt());
            userInfo.setProvince(result.get("province").asText());
            userInfo.setCity(result.get("city").asText());
            userInfo.setCountry(result.get("country").asText());
            userInfo.setHeadImgUrl(result.get("headimgurl").asText());
            
            return userInfo;
        } catch (Exception e) {
            throw new RuntimeException("解析用户信息失败: " + e.getMessage());
        }
    }
    
    public String getWebAccessToken(String code) {
        String url = String.format(
            "https://api.weixin.qq.com/sns/oauth2/access_token?appid=%s&secret=%s&code=%s&grant_type=authorization_code",
            appId, appSecret, code
        );
        
        String response = restTemplate.getForObject(url, String.class);
        try {
            JsonNode result = objectMapper.readTree(response);
            if (result.has("errcode")) {
                throw new RuntimeException("获取access_token失败: " + response);
            }
            return result.get("access_token").asText();
        } catch (Exception e) {
            throw new RuntimeException("解析响应失败: " + e.getMessage());
        }
    }
    
    /**
     * 初始化定时清理任务
     */
    @PostConstruct
    public void initCleanupTask() {
        // 启动定时清理任务，每5分钟清理一次过期的授权码
        new Thread(() -> {
            while (true) {
                try {
                    Thread.sleep(TimeUnit.MINUTES.toMillis(5));
                    cleanupExpiredCodes();
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                    break;
                }
            }
        }).start();
    }
    
    /**
     * 清理过期的授权码（超过10分钟的）
     */
    private void cleanupExpiredCodes() {
        long currentTime = System.currentTimeMillis();
        long expireTime = TimeUnit.MINUTES.toMillis(10); // 10分钟过期
        
        Iterator<Map.Entry<String, Long>> iterator = usedCodes.entrySet().iterator();
        while (iterator.hasNext()) {
            Map.Entry<String, Long> entry = iterator.next();
            if (currentTime - entry.getValue() > expireTime) {
                iterator.remove();
            }
        }
    }

}
